package com.authority.framework.log;

import com.authority.framework.web.domain.SysOperLogEntity;
import com.authority.framework.web.domain.SysUserEntity;
import com.authority.framework.web.service.SysOperLogService;
import com.authority.framework.base.util.*;
import com.authority.framework.base.util.address.AddressUtils;
import net.sf.json.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * @Description: 日志AOP存储
 * @Param:
 * @return:
 * @Author: Mr.Yan
 * @Date: 2018/9/21
 */

@Aspect
@Component
public class LogAspect {

	private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

	private static final ThreadLocal<Long> timeTreadLocal = new ThreadLocal<>();

	@Autowired
	private SysOperLogService sysOperLogService;

	//日志对象
	private SysOperLogEntity sysOperLog = new SysOperLogEntity();

	@Autowired
	private HttpServletRequest request;

	// controller层切点
	@Pointcut("@annotation(com.authority.framework.log.Log)")
	public void serviceAspect() {
	}

	@Before("serviceAspect()")
	public void doServiceBefore(JoinPoint joinPoint) throws Exception {
		timeTreadLocal.set(System.currentTimeMillis());
		// 获得注解
		Log annotationLog = getAnnotationLog(joinPoint);
		if (StringUtils.isNull(annotationLog)) {
			return;
		}

		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		//请求地址连接
		String uri = request.getRequestURI();
		// class 名称
		String className = joinPoint.getTarget().getClass().getName();
		//  地址 名称
		String methodName = joinPoint.getSignature().getName();
		// IP 地址
		String ip = ShiroUtils.getIp();
		//  iP地址
		String AddressByIP = AddressUtils.getRealAddressByIP(ip);
		//  获取当前时间
		String time = DateUtils.getTime();
		//  参数
		String operParam = setRequestValue();
		log.info("=====Service前置通知开始,方法：" + methodName + "=======");
		log.info("url ={}", uri);
		log.info("className  = {}", className);
		log.info("methodName  = {}", methodName);
		log.info("title  = {}", annotationLog.title());
		log.info("businessType  = {}", annotationLog.businessType());
		log.info("ip  = {}", ip);
		log.info("AddressByIP  = {}", AddressByIP);
		log.info("operParam  = {}", operParam);
		log.info("time  = {}", time);
		log.info("=====Service前置通知结束=====");

		//  获取登陆用户信息
		SysUserEntity userEntity = ShiroUtils.getSubjectUser();
		sysOperLog.setTitle(annotationLog.title());
		sysOperLog.setBusinessType(annotationLog.businessType().ordinal());
		sysOperLog.setMethod(className + "." + methodName + "()");
		sysOperLog.setOperName(userEntity.getUserName());
		sysOperLog.setDeptName(userEntity.getDept().getDeptName());
		sysOperLog.setOperUrl(uri);
		sysOperLog.setOperIp(ip);
		sysOperLog.setOperLocation(AddressByIP);
		sysOperLog.setOperParam(operParam);
		sysOperLog.setOperTime(time);

	}

	//controller请求结束返回时调用
	@AfterReturning(returning = "result", pointcut = "serviceAspect()")
	public void afterReturn(Object result) {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

		log.info("AOP afterReturn,返回值result = {}", result.toString());
		System.out.println("返回值=" + result.toString());
		long startTime = timeTreadLocal.get();
		double callTime = (System.currentTimeMillis() - startTime) / 1000.0;
		log.info("调用controller花费时间time = {}s", callTime);
		JSONObject jsonobj = JSONObject.fromObject(result);

		//  ResultModel 返回信息唯一码
		Object errcode = jsonobj.get("errcode");
		//  ResultModel 返回信息说明
		Object errmsg = jsonobj.get("errmsg");
		//  ResultModel 返回数据值
		Object data = jsonobj.get("data");

		log.info("errcode ={}", errcode);
		log.info("errmsg ={}", errmsg);
		log.info("data ={}", data);
		if (errmsg == null || errmsg == "") {
			errmsg = "暂无描述";
		}
		if(errcode.toString().equals("0")){
			//  正常
			sysOperLog.setStatus("0");
		}else{
			//  失败
			sysOperLog.setStatus("1");
		}
		sysOperLog.setErrorCode(errcode.toString());
		sysOperLog.setErrorMsg(errmsg.toString());
		sysOperLogService.insert(SysOperLogEntity.class,sysOperLog);
	}

	//controller请求异常返回时调用
	@AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
	public void doAfterThrowing(Throwable e) {
		log.info("AOP afterThrowing,返回未捕捉异常值message = {}", e.getMessage());
		System.out.println("返回异常值={}" + e.getMessage());
		long startTime = timeTreadLocal.get();
		double callTime = (System.currentTimeMillis() - startTime) / 1000.0;
		log.info("调用controller出现异常花费时间time = {}s", callTime);
		//  异常
		sysOperLog.setStatus("1");
		sysOperLog.setErrorCode("555");
		sysOperLog.setErrorMsg(e.getMessage());
		sysOperLogService.insert(SysOperLogEntity.class,sysOperLog);
	}

	/**
	 * 获取请求的参数，放到log中
	 */
	private String setRequestValue() {
		Map<String, String[]> map = ServletUtils.getRequest().getParameterMap();
		String params = com.alibaba.fastjson.JSONObject.toJSONString(map);
		return StringUtils.substring(params, 0, 255);
	}

	/**
	 * 是否存在注解，如果存在就获取
	 */
	private Log getAnnotationLog(JoinPoint joinPoint) throws Exception {
		Signature signature = joinPoint.getSignature();
		MethodSignature methodSignature = (MethodSignature) signature;
		Method method = methodSignature.getMethod();

		if (method != null) {
			return method.getAnnotation(Log.class);
		}
		return null;
	}
}
